 /*
 * KayleeMQ Messaging Service
 * Kevin Dagostino
 *
 *http://www.KayleeMQ.com
 *
 * Version 0.2   -   Updated: May 23, 2010
 *
 * This Plug-In provides access to the 'KayleeMQ messaging service.
 * It allows for simple connections, recieving, and publishing of messages in the browser.
 *
 *
 * This KayleeMQ messaging jQuery plug-in is dual licensed under the MIT and GPL licenses:
 *   do watcha pleases with it.
 *   
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 */

(function($,undefined){
	var _topic = 'testTopic';
	var _KayleeMQUrl = 'http://www.KayleeMQ.com/API';
	var _clientId = 
		//uuid-like
		'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
	    var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
	    return v.toString(16);
		});
	var _alias = "Anonymous";

	
	var exponential =  2;
	var connected = false;
	var reAttempterOptions;
	var firstTime = true;
	var timeDelay = Math.pow(2, exponential)*1000;
	var token = "";
	
	
	//This function attempts to reconnect after a suspected lost connection.
	clientConnectionReAttempter = function() {
		$("#debugConsole").append("<br> reconnector check called");
		if (connected == true){
			//TODO double check connection?
			exponential = 2;
			return;
		}
		$("#debugConsole").append("<br> Exponential: " + exponential + "  Attempting Reconnection " + timeDelay);
		exponential += 1;		
		timeDelay = Math.pow(2, exponential)*1000;
		$.fn.KayleeMQClient(reAttempterOptions);
	}
	
	var timeDelayBetweenHBrequests = 5000;
	var amountOfTimeThatPassesBeforeDeclaringDead = 10000;
	var dateOfLastMessageRecieved = new Date();

	sendMeHeartBeats = function() {
		if (!connected)
			return;
		
		$("#debugConsole").append("<br> send me a heartbeat called");
		var url = reAttempterOptions.KayleeMQUrl + '?sendMeAHeartBeat&clientId=' + reAttempterOptions.clientId;
		url += '&callback=?';
		$.getJSON(url, function(json){
			//TODO Check to see if we get a connection not found message..if so reissue token.
			$("#debugConsole").append("<br> sendMeAheartBeat Response: " + json.status);
			
		});
		setTimeout('sendMeHeartBeats()',  timeDelayBetweenHBrequests);

		
		var difference = new Date() - dateOfLastMessageRecieved;
		if (difference > amountOfTimeThatPassesBeforeDeclaringDead){
			connected = false;
			clientConnectionReAttempter;
			
		}
	}
	
	
	$.fn.KayleeMQClient = function(options) {
		$("#debugConsole").append('Starting');

		var defaults = {
			topic: _topic,
			clientId: _clientId,
			alias: _alias,
			KayleeMQUrl: _KayleeMQUrl,
			onOpen: function(){},
		  	onMessage: function(string){ return string; },
			onBuddyListUpdate: function(string){ return string; }
	  	};  
	 	var opts = $.extend(defaults, options);	 	
		
		//TODO consider moving this to publish and just checking if its already been made.
		$('<iframe />', {
    		name: 'KMQFrame',
   	 		id:   'KMQFrame',
			src:  'http://www.kayleeMQ.com/API',
			height: '0',
			width: '0',
			frameBorder: '0'
		}).appendTo('body');
	
		var tokenRequestUrl = opts.KayleeMQUrl + '?createToken&topic=' + opts.topic + '&clientId=' + opts.clientId;
		tokenRequestUrl += '&alias=' + opts.alias;

		if (opts.key)
			tokenRequestUrl += '&key=' + key;
		tokenRequestUrl += '&callback=?';

//		$("#debugConsole").append('<br>' + tokenRequestUrl);
		
		reAttempterOptions = defaults;
		
		setTimeout('clientConnectionReAttempter()',  timeDelay);
		setTimeout('sendMeHeartBeats()',  timeDelayBetweenHBrequests);

		if(token){
			attemptToOpenChannel();
		}
		else{
			$.getJSON(tokenRequestUrl, function(json){
				token = json.token;
				attemptToOpenChannel();
			});
		}
	}
	attemptToOpenChannel = function() {
		$("#debugConsole").append('<br> Attempting to open channel with ' + token);

		var channel = new goog.appengine.Channel(token);
		var socket = channel.open()
        socket.onopen = function() {
			connected = true;

			//$("#debugConsole").append('<br> on Open');
			if(typeof reAttempterOptions.onOpen == 'function'){
				reAttempterOptions.onOpen.call(this);
			}
        }
        socket.onmessage = function(evt) {
			var message = JSON.parse(evt.data); //jQuery.trim(evt.data);
			dateOfLastMessageRecieved = new Date();
			$("#debugConsole").append('<br> Message:  ' + message);
			$("#debugConsole").append('<br> Message:  ' + message.content);
			$("#debugConsole").append('<br> Message:  ' + message.id);

			//Handle HeartBeat Messages					
			if (message.type == 'heartbeat') {
				var heartbeatUrl = reAttempterOptions.KayleeMQUrl + '?heartbeat&token=' + token + '&callback=?';
				$.getJSON(heartbeatUrl, function(json){
					$("#debugConsole").append('<br> hbResponse:  ' + json.status);
					//If we are getting an error here, saying the connection no longer exists.. attempt to restart connection
					if (json.status == 'error'){
			    		reAttempterOptions.token = "";
						attemptToOpenChannel();						
					}
				});
			}
			else if (message.type == 'aliases') {
				if(typeof reAttempterOptions.onBuddyListUpdate == 'function'){
					reAttempterOptions.onBuddyListUpdate.call(this, message.content);
				}				
			}
			else if (message.type == 'message'){				
				//Send an ack message.
				var ackUrl = reAttempterOptions.KayleeMQUrl + '?ack&clientId=' + reAttempterOptions.clientId + '&messageId=' + message.id+ '&callback=?';
				$.getJSON(ackUrl, function(json){});
				
				if(typeof reAttempterOptions.onOpen == 'function'){
					reAttempterOptions.onMessage.call(this, message.content);
				}
			}
			else if (message.type == 'messageNotification'){
				//Grab real message
				var notificationUrl = reAttempterOptions.KayleeMQUrl + '?getMessage&clientId=' + reAttempterOptions.clientId + '&messageId=' + message.id+ '&callback=?';
				$.getJSON(notificationUrl, function(json){
					message = JSON.parse(json);
					//Send an ack message.
					var ackUrl = reAttempterOptions.KayleeMQUrl + '?ack&clientId=' + reAttempterOptions.clientId + '&messageId=' + message.id+ '&callback=?';
					$.getJSON(ackUrl, function(json){});
					
					//pass
					if(typeof reAttempterOptions.onOpen == 'function'){
						reAttempterOptions.onMessage.call(this, message.content);
					}
				});
			}
			
        }
        socket.onError = function() {
    		$("#debugConsole").append('Error Attempting to reOpen Channel');
    		connected = false;
    		reAttempterOptions.token = "";
			attemptToOpenChannel();    		
        }
        socket.onClose = function() {
    		$("#debugConsole").append('socket closed');
        }

	}
	
	$.fn.KayleeMQPublisher = function(options){
		var defaults = {
			topic: _topic,
			message: 'test message',
			KayleeMQUrl: _KayleeMQUrl,
			log: false
	  	};  
	 	var opts = $.extend(defaults, options);	

		var url = opts.KayleeMQUrl;
		
		var params ={
			createMessage: '1',
			topic: opts.topic,
			message: opts.message
		}
		
		postToUrl(url, params, true);
	}
	
	
	function postToUrl(url, params, newWindow)
	{
	    var form = $('<form>');
	    form.attr('action', url);
	    form.attr('method', 'POST');
	    if(newWindow){ form.attr('target', 'KMQFrame'); }
	
	    var addParam = function(paramName, paramValue){
	        var input = $('<input type="hidden">');
	        input.attr({ 'id':     paramName,
	                     'name':   paramName,
	                     'value':  paramValue });
	        form.append(input);
	    };
	
	    // Params is an Array.
	    if(params instanceof Array){
	        for(var i=0; i<params.length; i++){
	            addParam(i, params[i]);
	        }
	    }
	
	    // Params is an Associative array or Object.
	    if(params instanceof Object){
	        for(var key in params){
	            addParam(key, params[key]);
	        }
	    }
	
	    // Submit the form, then remove it from the page
	    form.appendTo(document.body);
	    form.submit();
	    //form.remove();
	}

	$.fn.KayleeMQUpdateAlias = function(options){
		var defaults = {
				alias: "Anonymous",
				KayleeMQUrl: _KayleeMQUrl,
				key: null,
				onRecieve: function(string){ return string; }			
		  	}; 
	 	var opts = $.extend(defaults, options);	

	 	

		//TODO:  Escape parameters
		var url = opts.KayleeMQUrl + '?updateAlias&clientId=' + reAttempterOptions.clientId + "&alias=" + opts.alias;
		url += '&callback=?';
		
		$.getJSON(url, function(json){
//	        $("#debugConsole").append(json);			

			if(typeof opts.onRecieve == 'function'){
				opts.onRecieve.call(this, json);
			}
		});
	}
	$.fn.KayleeMQGetLoggedMessages = function(options){
		var defaults = {
			topic: _topic,
			parameters: '',
			sort: '',
			range: '',
			KayleeMQUrl: _KayleeMQUrl,
			key: null,
			onRecieve: function(string){ return string; }			
	  	};  
	 	var opts = $.extend(defaults, options);	
		
		//TODO:  Escape parameters
		var url = opts.KayleeMQUrl + '?messageLogPull&topic=' + opts.topic;
		if (opts.parameters)
			url += '&parameters=' + encodeURI(opts.parameters);
		if (opts.sort)
			url += '&sort=' + encodeURI(opts.sort);
		if (opts.range)
			url += '&range=' + encodeURI(opts.range);
			
		url += '&callback=?';
		
		$.getJSON(url, function(json){
//	        $("#debugConsole").append(json);			

			if(typeof opts.onRecieve == 'function'){
				opts.onRecieve.call(this, json);
			}
		});
	}
	
	$.fn.KayleeMQPurgeMessagesOnTopic = function(options){
		var defaults = {
			topic: _topic,
			parameters: '',
			KayleeMQUrl: _KayleeMQUrl,
			key: null,
			onRecieve: function(string){ return string; }			
	  	};  
	 	var opts = $.extend(defaults, options);	
		
		//TODO:  Escape parameters
		var url = opts.KayleeMQUrl + '?purgeMessages&topic=' + opts.topic;
		url += '&callback=?';
		
		$.getJSON(url, function(json){
			
			if(typeof opts.onRecieve == 'function'){
				opts.onRecieve.call(this, json);
			}
		});
	}
})(jQuery);  	